/*
2011-10-25 by jieh
 1. 多國語言來源改整合 struts properties 檔案。

2011-10-23 by jieh
 1. 補完 show member all 功能。
 2. 補完多國語言支援。

2008-08-20 by jieh
 1. 解決 all 不能 keep 的 bug。
*/

package idv.jieh.commons.book;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

import org.apache.struts.Globals;
import org.apache.struts.util.PropertyMessageResources;

/**
 *
 * <p>Title: 藍色小惡魔的開發元件</p>
 *
 * <p>Description: </p>
 * web.xml 要加入 JiehQueryBookCtrl 的 servlet 設定。
 *
 * <p>Copyright: Copyright (c) 2011</p>
 *
 * <p>Company: BlueImp</p>
 *
 * @author Jieh
 * @version 1.0
 */
public class EasyBook extends idv.jieh.commons.comm.BasicClass {

  private HttpSession session;

  private QueryBook book;

  private boolean show_total_row = true;
  private boolean show_member_selection = true;
  private boolean show_pagination = true;
  private boolean show_form = false;
  private boolean show_member_all = true;

  /*
    每頁有些內容在每次點選頁面是不需要更新ㄉ，比如說：
    hidden 的兩個文字欄位。
    但是選單就會隨時變化，所以每次都必須動態產生 HTML 文字。
  */
  private StringBuffer cache = new StringBuffer();

  /*
    web.xml 要加入以下的設定。
    <servlet>
      <servlet-name>JiehQueryBookCtrl</servlet-name>
      <servlet-class>idv.jieh.commons.book.QueryBookCtrl</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>JiehQueryBookCtrl</servlet-name>
      <url-pattern>/JiehQueryBookCtrl</url-pattern>
    </servlet-mapping>
  */
  private String action = "JiehQueryBookCtrl";

  /** 網頁 form tag 的名稱 */
  private String text_pagination_head;
  private String text_pagination_end;
  private String text_member;
  private String text_previous;
  private String text_next;
  private String text_total_row;
  // 多國語言採用 struts properties 暫不開放由 properties 檔案變更初步設定。
  private String color_total_row = "blue";

  private enum NAME{
    NEXT("JIEHBOOK_NEXT"), PVIS("JIEHBOOK_PVIS"),
    HMC("JIEHBOOK_HIDDEN_MEMBER_CHANGE"), HPC("JIEHBOOK_HIDDEN_PAGINATION_CHANGE"),
    MS("JIEHBOOK_MEMBER_SELECTION"), PS("JIEHBOOK_PAGINATION_SELECTION"),

    ;

    private final String value;
    NAME(String s){value = s;}

    // 判斷是否是按下 上一頁 或 下一頁 的按鈕
    boolean isButton(HttpServletRequest request){
      return request.getParameter(value) != null;
    }
    // 判斷是否為改變了 每頁筆數 或 跳頁 的選單
    boolean isChange(HttpServletRequest request){
      String r = request.getParameter(value);
      return r != null && r.equals("1");
    }
    // 取得選單(每頁筆數 或 跳頁)中的數值
    int getChangeValue(HttpServletRequest request){
      return Integer.parseInt(request.getParameter(value));
    }
  }


  private enum MSG_KEY{
    TEXT_PAGINATION_HEAD("component.querybook.text.pagination.head"),
    TEXT_PAGINATION_END("component.querybook.text.pagination.end"),
    TEXT_MEMBER("component.querybook.text.member"),
    TEXT_PREVIOUS("component.querybook.text.previous"),
    TEXT_NEXT("component.querybook.text.next"),
    TEXT_TOTAL_ROW("component.querybook.text.total.row"),
//    COLOR_TOTAL_ROW("component.querybook.color.total.row"),

    ;

    private String key = null;

    private MSG_KEY(String key) {
      this.key = key;
    }

    public String key() {
      return key;
    }
  }

  // 筆數選單
  private idv.jieh.web.html.Selection member_selection = new idv.jieh.web.html.Selection();
  // 筆數選單：最少顯示筆數，內定值 5 筆。
  private int member_begin = 5;
  // 筆數選單：最多顯示筆數，內定值 100 筆。
  private int member_end = 100;
  // 設定總筆數選單最大值到最小值之間顯示的間隔，內定 5。
  private int member_interval = 5;

  // 跳頁選單
  private idv.jieh.web.html.Selection pagination_selection = new idv.jieh.web.html.Selection();
  // 放到 session 的名稱。
  private String sessionKey = "JIEH_WEB_BOOK";
  // HTML Form name
  private String formName = "form";

  public EasyBook(HttpSession session){
    init(session);
  }

  public EasyBook(HttpSession session, QueryBook book) {
    init(session);
    session.setAttribute(sessionKey, book);
    book.next();
  }

  private void init(HttpSession session){
    this.session = session;

    PropertyMessageResources message = (PropertyMessageResources)session.getServletContext().getAttribute(Globals.MESSAGES_KEY);
    java.util.Locale locale = (java.util.Locale)session.getAttribute(org.apache.struts.Globals.LOCALE_KEY);

    this.text_pagination_head = message.getMessage(locale, MSG_KEY.TEXT_PAGINATION_HEAD.key());
    this.text_pagination_end = message.getMessage(locale, MSG_KEY.TEXT_PAGINATION_END.key());
    this.text_member = message.getMessage(locale, MSG_KEY.TEXT_MEMBER.key());
    this.text_previous = message.getMessage(locale, MSG_KEY.TEXT_PREVIOUS.key());
    this.text_next = message.getMessage(locale, MSG_KEY.TEXT_NEXT.key());
    this.text_total_row = message.getMessage(locale, MSG_KEY.TEXT_TOTAL_ROW.key());
  }


  // 執行翻頁的動作。
  public static boolean isBook(HttpServletRequest request, HttpSession session)
    throws ServletException, IOException {

    // 必須修改為比較複雜的名稱
    String name = request.getParameter("bn");
    // add 2006-08-15 by jieh : 在不同的 J2EE 平台 request 取無資料時會給 null 或 空字串 不一定。
    if(idv.jieh.commons.util.DataAnalysis.trimNull(name).length() == 0) return false;
    QueryBook book = (QueryBook) session.getAttribute(name);

    // 下一頁
    if (NAME.NEXT.isButton(request)) {
      book.next();

    // 上一頁
    } else if (NAME.PVIS.isButton(request)) {
      book.previous();

    // 筆數變換
    } else if (NAME.HMC.isChange(request)) {
      int size = NAME.MS.getChangeValue(request);
      book.setMember(size==-1?book.getTotalRow():size);
      book.next();

    // 跳頁變換
    } else if (NAME.HPC.isChange(request)) {
      int pagination = NAME.PS.getChangeValue(request);
      book.setPagination(pagination - 1);
      book.next();
    }else{
      return false;
    }
    return true;
  }

  /**
   * 利用 <code>TableCache</code> 產生 <code>QueryBook</code> 放置到 Session。<p>
   * 如果需要變更 Session key 的話可以呼叫 <code>setSessionKey(String)</code>。
   * @param tc TableCache
   * @return boolean 回應產生的 <code>QueryBook</code> 是否有資料，true：有；false：無。
   */
  public boolean putQueryBook(idv.jieh.commons.sql.TableCache tc){
    QueryBook book = new QueryBook(tc);
    session.setAttribute(sessionKey, book);
    return book.next();
  }

  /**
   * 從 session 中取出 <code>QueryBook</code> 後回傳。
   * @return QueryBook
   */
  public QueryBook getQueryBook(){
    return (QueryBook) session.getAttribute(sessionKey);
  }

  /**
   * 從 session 中的 <code>QueryBook</code> 取出 <code>QueryPage</code> 後回傳。
   * @return QueryPage
   */
  public QueryPage getQueryPage(){
    QueryBook book = getQueryBook();
    return book.getQueryPage();
  }

  /**
   * 顯示分頁元件到網頁上。<p>
   * 如果所有屬性都設定好了，就可以在網頁的適當地方，呼叫這個方法。這個方法將會傳回準備好
   * 的分頁元件，撰寫成合法的 HTML code 回傳，網頁即將會顯現出你想要的完美元件。<p>
   * 呼叫這個方法之前請先準備好 <i>javax.servlet.http.HttpServletRequest</i> 這個物
   * 件，並傳入。
   * @param rq <i>javax.servlet.http.HttpServletRequest</i>。
   * @return 合法的 HTML code。
   */
  public String show(javax.servlet.http.HttpServletRequest rq) {
    this.book = (idv.jieh.commons.book.QueryBook)session.getAttribute(sessionKey);

    makeMemberSelection();
    makePaginationSelection();

    StringBuilder r = new StringBuilder();

    if(show_form){this.addForm(r);}

    // 設定隱藏欄位
    addHidden(r, rq.getRequestURI());
    // 顯示總筆數
    if (this.show_total_row) {
      r.append(this.text_total_row);
      r.append("<font color='").append(this.color_total_row).append("'>");
      r.append(book.getTotalRow()).append("</font>, ");
    }

    // 筆數選單
    if (this.show_member_selection) {
      r.append(text_member).append(member_selection.show());
    }

    // 上一頁下一頁按鈕
    this.addButton(r, NAME.PVIS.value, this.text_previous, book.showPreviousButton());
    this.addButton(r, NAME.NEXT.value, this.text_next, book.showNextButton());

    // 跳頁選單
    if (this.show_pagination) {
      r.append(text_pagination_head).append(" ");
      r.append(pagination_selection.show());
      r.append(" ").append(text_pagination_end);
    }

    if(show_form){r.append("</form>");}

    return r.toString();
  }

  private void addForm(StringBuilder r) {
    r.append("<form name='").append(formName).append("' action='").append(action).append("'>");
  }

  private void addHidden(StringBuilder r, String pvispage) {
    // <input type='hidden' name='pvispage' value='[pvispage]'>
    // 讓 PageCtrl 做完動作後知道要把網頁導回要求的頁面
    r.append("<input type='hidden' name='pvispage' value='").append(pvispage).append("'>");

    // 紀錄 QueryBook 放在 session 的名稱，這是 PageCtrl 需要取得的資訊
    r.append("<input type='hidden' name='bn' value='").append(sessionKey).append("'>");

    // 每頁筆數
    hidden(r, NAME.HMC.value);
    // 跳頁
    hidden(r, NAME.HPC.value);
  }

  private void hidden(StringBuilder r, String name) {
    r.append("<input type='hidden' name='").append(name).append("' value='0'>");
  }


  //	<input type="submit" name="PvisPage" value="上一頁">
  // 	<input type="submit" name="NextPage" value="下一頁">
  private void addButton(StringBuilder r, String name, String value, boolean show) {
    r.append(" <input type='submit' name='").append(name);
    r.append("' value='").append(value).append("'");
    if (!show) {
      r.append(" disabled");
    }
    r.append("> ");
  }

  // 設定筆數選單物件。
  private void makeMemberSelection() {
    member_selection.setName(NAME.MS.value);
    member_selection.setNumberRange(member_begin, member_end, member_interval);
    member_selection.setScript(onChange(NAME.HMC.value));
    int member = book.getMember();
    if(this.show_member_all){
      // 2008-08-20 by jieh : 解決 all 不能 keep 的 bug。
      if(member == book.getTotalRow()){
        member = -1;
      }
      member_selection.addContent("-1", "all");
    }
    member_selection.setSelected(String.valueOf(member));
  }

  // 設定跳頁選單物件。
  private void makePaginationSelection() {
    pagination_selection.setName(NAME.PS.value);
    pagination_selection.setNumberRange(1, book.getTotalPage());
    pagination_selection.setScript(onChange(NAME.HPC.value));
    pagination_selection.setSelected(String.valueOf(book.getPagination()));
  }

  // onChange = 'document.epPageCtrl.pschange.value = 1;document.epPageCtrl.submit();'
  // 傳入 hidden 欄位的名稱，pschangehidden / gopgchangehidden。
  private String onChange(String name) {
    StringBuffer r = new StringBuffer();
    r.append("onChange = 'document.").append(formName).append(".").append(name).append(".value = 1;");
    r.append("document.").append(formName).append(".submit();'");
    return r.toString();
  }

  /**
   * 設定是否要顯示總筆數的內容。<p>
   * @param s true：要顯示；false：不顯示。
   */
  public void showTotalRow(boolean s) {
    this.show_total_row = s;
  }

  /**
   * 設定是否要開放筆數選單的功能。<p>
   * @param s true：要顯示；false：不顯示。
   */
  public void showMemberSelection(boolean s) {
    this.show_member_selection = s;
  }


  /**
   * 設定筆數選單是否提供 all 選項。<p>
   * @param s true：要顯示；false：不顯示。
   */
  public void showMemberAll(boolean s){
    this.show_member_all = s;
  }

  /**
   * 設定是否要產生 HTML FORM TAG。<p>
   * @param s true：要產生；false：不產生。
   */
  public void showForm(boolean s){
    show_form = s;
  }

  /**
   * 設定是否要開放跳頁選單的功能。<p>
   * @param s true：要顯示；false：不顯示。
   */
  public void showPagination(boolean s) {
    this.show_pagination = s;
  }

  /**
   * 設定筆數選單的範圍，內定值是 5 - 100。<p>
   * 會依照間隔產生一數列，若是預定值，將會產生 5,10,15,20 這一數列。
   * @param begin 筆數選單的開始範圍。
   * @param end 筆數選單的結束範圍。
   */
  public void setMemberRange(int begin, int end) {
    this.member_begin = begin;
    this.member_end = end;
  }

  /**
   * form action URL。<p>
   * 這是設定被砍入分頁元件的 JSP form action URL，內定值是
   * [<font color='red'>/servlet/com.exentric.book.PageCtrl</font>]，如果有自訂
   * Controler 的話，就需要更改到這
   * 個設定值。
   * @param action 一個可以控制分頁動作的 Controler 路徑。
   */
  public void setAction(String action) {
    this.action = action;
  }

  /**
   * 設定使用者總筆數選單的間隔值。<p>
   * 設定總筆數選單最大值到最小值之間顯示的間隔，內定 5。
   * @param s 指定的使用者總筆數選單的間隔值。
   */
  public void setMemberInterval(int s){
    this.member_interval = s;
  }

  /**
   * <i>QueryBook</i> 放到 session 的名稱。<p>
   * 內定值是 JIEH_WEB_BOOK。如果有改變 session 名稱的話，就必須在這個方法宣告改變後的名稱。
   * @param bookName 修改後的 session 名稱。
   */
  public void setSessionKey(String bookName) {
    this.sessionKey = bookName;
  }

  /**
   *
   * @param name String
   */
  public void setFormName(String name){
    this.formName = name;
  }

} // end class EasyBook
